package cc.rengu.igas.share.core.service.channel.wechat;

import cc.rengu.igas.channel.wechat.facade.base.Header;
import cc.rengu.igas.channel.wechat.facade.bean.TerminalInfo;
import cc.rengu.igas.channel.wechat.facade.request.WechatMircopayRequest;
import cc.rengu.igas.channel.wechat.facade.response.WechatMicropayResponse;
import cc.rengu.igas.channel.wechat.facade.result.Result;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.common.constant.ShareServiceConstant;
import cc.rengu.igas.share.common.enums.FeeTypeEnum;
import cc.rengu.igas.share.common.enums.WechatPayStatusEnum;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * 微信被扫
 * Created by lzl on 2021/4/23 11:08
 */
public class MircopayService extends ChannelBaseService {
    @Override
    public Object callPreProc(TxnInfo txnInfo, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        Header wxHeader = new Header();
        wxHeader.setInstId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID));
        wxHeader.setChanlId(channelCallCfg.getMsgSrcId());
        wxHeader.setSrcSysId(AppParamConstant.SYS_ID);
        wxHeader.setBizType(AppParamConstant.DEFAULT_BIZ_TYPE);
        wxHeader.setVersion(ShareParamConstant.DUBBO_VSERSION);
        wxHeader.setTxnNum(channelCallCfg.getCallChannelTxn());
        wxHeader.setTraceNo(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM) + channelCallCfg.getCallIndex());
        wxHeader.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        wxHeader.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));

        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(wxHeader.getInstId(), xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.MCHNT_NO));
        WechatMircopayRequest wechatMircopayRequest = new WechatMircopayRequest();
        ConvertUtil.convertOutput(wechatMircopayRequest);
        wechatMircopayRequest.setHeader(wxHeader);
        wechatMircopayRequest.setPayQrCode(xmlTreeUtil.getXmlTreeStringValue("payQrCode"));
        wechatMircopayRequest.setOrderId(wxHeader.getTraceNo());
        wechatMircopayRequest.setOrderAmt(orderInfo.getUserOrderInfo().getRealPayAmt());

        wechatMircopayRequest.setChannelId(channelCallCfg.getCallChannelId());
        wechatMircopayRequest.setChannelType(mchntInfo.getWechatChannelType());
        wechatMircopayRequest.setMchntNo(mchntInfo.getMchntNo());
        wechatMircopayRequest.setTermNo(orderInfo.getMchntOrderInfoList().get(0).getTermNo());
        wechatMircopayRequest.setThirdMchntNo(mchntInfo.getWechatMchntNo());
        /*扫码支付 子appId不上送*/
        wechatMircopayRequest.setSubAppId("");
        wechatMircopayRequest.setOrderId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
        wechatMircopayRequest.setOrderAmt(orderInfo.getUserOrderInfo().getRealPayAmt());
        wechatMircopayRequest.setOrderCcy("CNY");
        wechatMircopayRequest.setTermIp(xmlTreeUtil.getXmlTreeStringValue("riskInfo/termIp"));
        wechatMircopayRequest.setGoodDesc(orderInfo.getUserOrderInfo().getOrderDesc());
        wechatMircopayRequest.setTimeExpr(orderInfo.getUserOrderInfo().getOrderExpiryTime());
        if (xmlTreeUtil.isExist("limitPay")) {
            wechatMircopayRequest.setLimitPay(xmlTreeUtil.getXmlTreeStringValue("limitPay"));
        }
        // 259号文监管新增字段
        wechatMircopayRequest.setMchntName(mchntInfo.getMchntName());
        wechatMircopayRequest.setAreaInfo(mchntInfo.getMchntBizRegion());
        /* 设置终端信息 */
        TerminalInfo terminalInfo = new TerminalInfo();
        // 终端设备实时经纬度信息,格式为纬度/经度
        String latitude = xmlTreeUtil.getXmlTreeStringValue("termInfo/latitude");
        String longitude = xmlTreeUtil.getXmlTreeStringValue("termInfo/longitude");
        if (!StringUtil.isEmptyOrNull(latitude) && !StringUtil.isEmptyOrNull(longitude)) {
            terminalInfo.setLocation(latitude + "/" + longitude);
        }
        terminalInfo.setNetworkLicense(xmlTreeUtil.getXmlTreeStringValue("termInfo/networkLicense"));
        terminalInfo.setDeviceType(orderInfo.getMchntOrderInfoList().get(0).getTermType());
        terminalInfo.setSerialNum(xmlTreeUtil.getXmlTreeStringValue("termInfo/serialNum"));
        terminalInfo.setDeviceId(orderInfo.getMchntOrderInfoList().get(0).getTermNo());
        terminalInfo.setEncryptRandNum(xmlTreeUtil.getXmlTreeStringValue("termInfo/encryptRandNum"));
        terminalInfo.setSecretText(xmlTreeUtil.getXmlTreeStringValue("termInfo/secretText"));
        terminalInfo.setAppVersion(xmlTreeUtil.getXmlTreeStringValue("termInfo/appVersion"));
        terminalInfo.setDeviceIp(xmlTreeUtil.getXmlTreeStringValue("termIp"));
        wechatMircopayRequest.setTerminalInfo(terminalInfo);
        rglog.debug("微信扫码请求:<{}>", JSON.toJSONString(wechatMircopayRequest));
        return wechatMircopayRequest;
    }

    @Override
    public PayOrderInfo generatePayOrderInfo(ChannelCallCfg channelCallCfg, OrderInfo orderInfo, Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        PayOrderInfo payOrderInfo = new PayOrderInfo();
        WechatMircopayRequest wechatMircopayRequest = (WechatMircopayRequest) request;
        BeanUtil.beanCopy(orderInfo.getUserOrderInfo(), payOrderInfo);
        if (orderInfo.getMchntOrderInfoList().size() == 1) {
            payOrderInfo.setMchntNo(orderInfo.getMchntOrderInfoList().get(0).getMchntNo());
        } else {
            payOrderInfo.setMchntNo(orderInfo.getUserOrderInfo().getGroupMchntNo());
        }
        payOrderInfo.setTxnNum(channelCallCfg.getTxnNum());
        payOrderInfo.setBizType(channelCallCfg.getBizType());
        payOrderInfo.setSysSeqNum(orderInfo.getUserOrderInfo().getSysSeqNum());
        payOrderInfo.setOrderCcy(orderInfo.getUserOrderInfo().getOrderCcy());
        payOrderInfo.setMsgDstId(channelCallCfg.getCallChannelId());
        payOrderInfo.setDstCallIndex(channelCallCfg.getCallIndex());
        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(wechatMircopayRequest.getHeader().getInstId(), xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.MCHNT_NO));
        payOrderInfo.setDstChannelType(mchntInfo.getWechatChannelType());
        payOrderInfo.setChannelSeqNum(wechatMircopayRequest.getHeader().getTraceNo());
        payOrderInfo.setChannelReconKey(orderInfo.getUserOrderInfo().getSysSeqNum());
        payOrderInfo.setDstTxnNum(channelCallCfg.getCallChannelTxn());
        payOrderInfo.setPayType(PayTypeEnum.WECHAT.getPayType());
        payOrderInfo.setPayerAcctType(AcctTypeEnum.ALL.getAcctType());
        payOrderInfo.setPayerAcctInfo(wechatMircopayRequest.getPayQrCode());
        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        payOrderInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        payOrderInfo.setUserId(orderInfo.getUserOrderInfo().getUserId());
        return payOrderInfo;
    }

    @Override
    public Object callProc(ChannelCallCfg channelCallCfg, Object request) throws Exception {
        WechatMircopayRequest wechatMircopayRequest = (WechatMircopayRequest) request;
        /* Step1：调用接口，获取结果 */
        Result<WechatMicropayResponse> callResult;
        DubboService dubboService = new DubboServiceImpl();
        if (AppParamConstant.YES.equals(channelCallCfg.getSyncCallFlag())) {
            /* Step1.1：异步调用 */
            int iReturnCode;
            int callTimes = 0 == channelCallCfg.getSyncQueryRepeatNum() ? 1 : channelCallCfg.getSyncQueryRepeatNum();
            int gatTime = channelCallCfg.getSyncQueryRepeatTime();
            int gatType = StringUtil.isEmptyOrNull(channelCallCfg.getSyncQueryGapType()) ? 0 : Integer.parseInt(channelCallCfg.getSyncQueryGapType());
            if (ChannelCallModeEnum.LOCAL.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.1.1：异步应用内调用 */
                Class clasz = Class.forName(ShareServiceConstant.WECHAT_PAY_SERVICE_INNER_PATH);
                iReturnCode = dubboService.asynCallDubboInnerMethod(clasz, ShareServiceConstant.WECHAT_MICROPAY_METHOD, wechatMircopayRequest, channelCallCfg.getSyncResultServiceName(), callTimes, gatType, gatTime);
            } else if (ChannelCallModeEnum.REMOTE.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.1.2：异步远程调用 */
                iReturnCode = dubboService.asynCallDubboService(ShareServiceConstant.WECHAT_PAY_SERVICE, ShareServiceConstant.WECHAT_MICROPAY_METHOD, wechatMircopayRequest, channelCallCfg.getSyncResultServiceName(), callTimes, gatType, gatTime);
            } else {
                rglog.error("不支持的通道服务调用方式:{}，交易拒绝!", channelCallCfg.getChannelCallMode());
                throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR);
            }
            if (0 == iReturnCode) {
                return new BizResponse<>(OltpRpcdEnum.TRANS_SUCCESS.getRespCode(), OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
            } else {
                return new BizResponse<>(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
            }
        } else {
            /* Step1.2：同步调用 */
            if (ChannelCallModeEnum.LOCAL.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.2.1：同步应用内调用 */
                Class clasz = Class.forName(ShareServiceConstant.WECHAT_PAY_SERVICE_INNER_PATH);
                callResult = (Result<WechatMicropayResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.WECHAT_MICROPAY_METHOD, wechatMircopayRequest);
            } else if (ChannelCallModeEnum.REMOTE.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.2.2：同步远程调用 */
                callResult = (Result<WechatMicropayResponse>) dubboService.callDubboService(ShareServiceConstant.WECHAT_PAY_SERVICE, ShareServiceConstant.WECHAT_MICROPAY_METHOD, wechatMircopayRequest);
            } else {
                rglog.error("不支持的通道服务调用方式:{}，交易拒绝!", channelCallCfg.getChannelCallMode());
                throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR);
            }
        }
        return callResult;
    }

    @Override
    public Object querySyncCallResult(PayOrderInfo payOrderInfo, Object request) {
        return null;
    }

    @Override
    public OrderInfo callResultOrderProc(OrderInfo orderInfo, String payOrderIndex, TransStatusEnum transStatusEnum, Object response) throws Exception {
        OrderInfo updateOrderInfo = new OrderInfo();
        Result<WechatMicropayResponse> callResult = (Result<WechatMicropayResponse>) response;
        Optional<PayOrderInfo> payOrderInfoOpt = orderInfo.getPayOrderInfoList().stream().filter(item -> item.getDstCallIndex().equals(payOrderIndex)).findFirst();
        if (payOrderInfoOpt.isPresent() && null != callResult && null != callResult.getResult()) {
            WechatMicropayResponse wechatMicropayResponse = callResult.getResult();
            UserOrderInfo userOrderInfo = orderInfo.getUserOrderInfo();
            List<MchntOrderInfo> mchntOrderInfoList = orderInfo.getMchntOrderInfoList();
            PayOrderInfo payOrderInfo = payOrderInfoOpt.get();
            payOrderInfo.setTransStatus(transStatusEnum.getStatus());
            payOrderInfo.setRespCode(wechatMicropayResponse.getRespCode());
            payOrderInfo.setRespDesc(wechatMicropayResponse.getRespDesc());
            payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            switch (transStatusEnum) {
                case TRANS_SUCC:
                    if (WechatPayStatusEnum.SUCCESS.getStatus().equals(wechatMicropayResponse.getTradeState())) {
                        rglog.info("原微信支付交易支付成功,oriTransTradeState:<{}>", wechatMicropayResponse.getTradeState());
                        /* 更新支付订单信息 */
                        userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
                        userOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                        userOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
                        userOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        /* 更新商户订单信息 */
                        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
                            mchntOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                            mchntOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
                            mchntOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        }
                        /* 判断商户是否在通道有配置营销,若有配置，则需要更新商户订单信息 */
                        String mchntDiscAmt = "0";
                        if (!StringUtil.isEmptyOrNull(wechatMicropayResponse.getSettleAmt())) {
                            mchntDiscAmt = AmountUtil.subtraction(payOrderInfo.getRealPayAmt(), wechatMicropayResponse.getSettleAmt());
                        }
                        if (AmountUtil.compare(mchntDiscAmt, "0.00") == 1) {
                            /* 更新用户订单表中的实际支付金额及实际优惠金额 */
                            userOrderInfo.setRealDiscountAmt(AmountUtil.addition(userOrderInfo.getRealDiscountAmt(), mchntDiscAmt));
                            userOrderInfo.setRealPayAmt(AmountUtil.subtraction(userOrderInfo.getRealPayAmt(), mchntDiscAmt));
                            /* 计算每个商户的优惠金额 */
                            String mchntPerDiscAmt = AmountUtil.division(mchntDiscAmt, String.valueOf(mchntOrderInfoList.size()), 2);
                            String lastMchntRealSettleAmt = mchntOrderInfoList.get(mchntOrderInfoList.size() - 1).getRealSettleAmt();
                            mchntOrderInfoList.forEach(item -> item.setRealSettleAmt(AmountUtil.subtraction(item.getRealSettleAmt(), mchntPerDiscAmt)));
                            /* 重新赋值最后一个商户的实际清算本金 */
                            String lastMchntDiscAmt = AmountUtil.subtraction(mchntDiscAmt, AmountUtil.multiplication(mchntPerDiscAmt, String.valueOf(mchntOrderInfoList.size() - 1), 2));
                            mchntOrderInfoList.get(mchntOrderInfoList.size() - 1).setRealSettleAmt(AmountUtil.subtraction(lastMchntRealSettleAmt, lastMchntDiscAmt));
                            /* 若商户有计算手续费，则重新计算商户手续费 */
                            MchntService mchntService = new MchntServiceImpl();
                            mchntService.calcMchntFee(mchntOrderInfoList, FeeTypeEnum.WECHAT.getFeeType());
                        }
                        updateOrderInfo.setUserOrderInfo(userOrderInfo);
                        updateOrderInfo.setMchntOrderInfoList(mchntOrderInfoList);
                        /* 更新支付订单信息 */
                        payOrderInfo.setPayerAcctType(AcctTypeEnum.ALL.getAcctType());
                        SysParamService sysParamService = new SysParamServiceImpl();
                        SysParam sysParam = sysParamService.getSysParamInfo(payOrderInfo.getInstId(), "WCHAT_CARDTYPE", wechatMicropayResponse.getBankType());
                        if (wechatMicropayResponse.getBankType().contains("DEBIT")) {
                            payOrderInfo.setPayerAcctType((null == sysParam) ? AcctTypeEnum.OTHER_DEBIT.getAcctType() : AcctTypeEnum.BANK_DEBIT.getAcctType());
                        } else if (wechatMicropayResponse.getBankType().contains("CREDIT")) {
                            payOrderInfo.setPayerAcctType((null == sysParam) ? AcctTypeEnum.OTHER_CREDIT.getAcctType() : AcctTypeEnum.BANK_CREDIT.getAcctType());
                        }
                        payOrderInfo.setPayerAcctInfo("微信用户");
                        payOrderInfo.setRespCode(wechatMicropayResponse.getRespCode());
                        payOrderInfo.setRespDesc(wechatMicropayResponse.getRespDesc());
                        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                        payOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
                        payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                    } else if (WechatPayStatusEnum.USERPAYING.getStatus().equals(wechatMicropayResponse.getTradeState())) {
                        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                    } else {
                        /* 更新当前用户订单信息 */
                        userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
                        userOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                        userOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                        userOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        /* 更新当前商户订单信息 */
                        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
                            mchntOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                            mchntOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                            mchntOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        }
                        /* 更新当前支付订单信息 */
                        payOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                        payOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                        payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        updateOrderInfo.setUserOrderInfo(userOrderInfo);
                        updateOrderInfo.setMchntOrderInfoList(mchntOrderInfoList);
                    }
                    break;
                case TRANS_TIMEOUT:
                    payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                    break;
                case SYSTEM_REJECT:
                    /* 更新当前用户订单信息 */
                    userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
                    userOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                    userOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                    userOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                    /* 更新当前商户订单信息 */
                    for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
                        mchntOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                        mchntOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                        mchntOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                    }
                    /* 更新当前支付订单信息 */
                    payOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                    payOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                    payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                    updateOrderInfo.setUserOrderInfo(userOrderInfo);
                    updateOrderInfo.setMchntOrderInfoList(mchntOrderInfoList);
                    break;
                default:
                    break;
            }
            updateOrderInfo.setPayOrderInfoList(Collections.singletonList(payOrderInfo));
        }
        return updateOrderInfo;
    }
}
